package com.example.Service.Impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.Service.ImageService;
import com.example.entity.dto.Account;
import com.example.mapper.AccountMapper;

import io.minio.GetObjectArgs;
import io.minio.GetObjectResponse;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

/**
 * 作者:xuSen
 * 日期2025/4/25 12:52
 */
// 使用slf4j日志框架记录日志
// 标注为Spring的Service组件，表明这是一个被Spring管理的Bean
@Slf4j
@Service
public class ImageServiceImpl implements ImageService {

    // 注入MinioClient实例，用于与Minio服务器进行交互
    @Resource
    private MinioClient minioClient;

    // 注入AccountMapper实例，用于操作Account相关的数据库表
    @Resource
    private AccountMapper accountMapper;

    /**
     * 上传用户头像
     * 该方法接收一个multipart文件和用户ID，将文件上传到MinIO对象存储，并更新用户数据库中的头像URL
     * 如果上传和更新操作成功，返回头像的URL；如果失败，返回null
     * @param file 用户上传的头像文件
     * @param id 用户ID，用于确定哪个用户的头像需要更新
     * @return 成功上传后的头像URL，如果上传失败则返回null
     * @throws IOException 如果文件读取过程中发生错误
     */
    @Override
    public String uploadAvatar(MultipartFile file, int id) throws IOException {
        // 生成一个唯一的后缀名，用于避免文件名冲突
        String imageName = UUID.randomUUID().toString().replace("-", "");
        imageName = "/avatar/" + imageName;
        // 构建上传参数，准备将文件上传到MinIO
        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket("study") // 指定存储桶名称
                .stream(file.getInputStream(), file.getSize(), -1) // 设置文件流和文件大小
                .object(imageName) // 设置对象名，即文件在MinIO中的路径
                .build();
        try {
            // 执行文件上传操作
            minioClient.putObject(putObjectArgs);
            // 更新用户数据库中的头像URL
            if(accountMapper.update(null, Wrappers.<Account>update()
                    .eq("id",id).set("avatar",imageName))>0){
                return imageName; // 如果更新成功，返回头像URL
            }else {
                return null; // 如果更新失败，返回null
            }
        } catch (Exception e) {
            // 记录上传失败的日志信息
            log.error("上传失败"+e.getMessage(),e);
            return null; // 上传失败，返回null
        }
    }

    /**
     * 从Minio服务器获取图片
     *
     * @param outputStream 输出流，用于接收从Minio服务器获取的图片数据
     * @param image 图片的名称，用于在Minio服务器的存储桶中唯一标识该图片
     * @throws IOException 当读写数据发生错误时抛出
     * @throws ServerException 当Minio服务器发生错误时抛出
     * @throws InsufficientDataException 当接收到的数据量少于预期时抛出
     * @throws ErrorResponseException 当Minio服务器返回错误响应时抛出
     * @throws NoSuchAlgorithmException 当指定的加密算法不存在时抛出
     * @throws InvalidKeyException 当指定的加密密钥无效时抛出
     * @throws InvalidResponseException 当Minio服务器返回的响应无效时抛出
     * @throws XmlParserException 当解析XML响应发生错误时抛出
     * @throws InternalException 当发生内部错误时抛出
     */
    @Override
    public void fetchImageFromMinio(OutputStream outputStream, String image) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        // 构建获取对象的参数，指定存储桶和图片名称
        GetObjectArgs test = GetObjectArgs.builder()
                .bucket("study")
                .object(image)
                .build();
        // 使用Minio客户端获取对象（图片）
        GetObjectResponse object = minioClient.getObject(test);
        // 将获取到的图片数据复制到输出流中
        IOUtils.copy(object, outputStream);
    }
}

















